home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_400
/
432_01
/
ptmid3
/
ptmidinp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-05
|
15KB
|
534 lines
/*
* ptmidinp.c: MIDI input module for for ptmid. Reads a MIDI file and
* creates a structure representing it.
*
* Author: Andrew Scott (c)opyright 1994
*
* Date: 17/11/1993 ver 0.0
* 8/1/1994 ver 0.1
* 11/2/1994 ver 0.2
*/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <string.h>
#include "ptmid.h"
#define BUFSIZ 512
#define ODD(x) (x & 1)
typedef unsigned long VLQ; /** VLQ is a variable length quantity **/
typedef struct { /** RF is a record of a file **/
int fd, ib;
unsigned char rgb[BUFSIZ];
} RF;
int rgbPatch[16], wDivision, wBendsen = 2, wModwheel = 0;
unsigned wQuant;
NRL *rgpnrl[16][128];
Tune *ptuneMain, *ptuneCurr;
RF *prf;
/*
* Init: Yes.. you guessed it. Initializes variables and stuff.
*
* date: 30/6/1994 - added 16 NRL array init
*/
static void Init(void)
{
int i, j;
for (i = 16; i--; ) { /** Clear current instrument array **/
rgbPatch[i] = 0;
for (j = 128; j--; ) /** Clear hanging-note arrays **/
rgpnrl[i][j] = NULL;
}
}
/*
* ChGetFd: Given a file, returns next character from it.
*/
int ChGetFd(int fd)
{
unsigned char b;
if (read(fd, &b, 1) < 1)
return EOF;
return b;
}
/*
* ChGetIrf: Given an index, returns next character from corresponding
* file record.
*/
unsigned char ChGetIrf(unsigned irf)
{
if (prf[irf].ib == BUFSIZ) {
if (read(prf[irf].fd, prf[irf].rgb, BUFSIZ) == -1) {
ERROR;
exit(1);
}
prf[irf].ib = 1;
return prf[irf].rgb[0];
}
return prf[irf].rgb[prf[irf].ib++];
}
/*
* SkipIrf: Given an index, skips a given number of bytes forward in
* that file record.
*
* date: 4/7/1994 - fixed longstanding bug: wouldn't read in new buffer
*/
void SkipIrf(unsigned irf, long cb)
{
if (BUFSIZ - prf[irf].ib >= cb)
prf[irf].ib += (int) cb;
else {
cb -= BUFSIZ - prf[irf].ib;
if (lseek(prf[irf].fd, cb, SEEK_CUR) == -1) {
ERROR;
exit(1);
}
prf[irf].ib = BUFSIZ;
}
}
/*
* ValidquantSz: Takes a lower-case string and checks to see if it is a
* legal quantize fraction. If not, zero is returned, else value of
* string is returned (+1 if a triplet case).
*/
int ValidquantSz(Sz szQuant)
{
int bFrac;
Sz szEnd;
if ((bFrac = (int) strtol(szQuant, &szEnd, 10))) /** If a number **/
if ('t' == *szEnd || 'T' == *szEnd) /** possibly followed by a 't' **/
bFrac++;
return bFrac; /** return valid **/
}
/*
* VlqFromFd: Reads bytes from given file until a variable length
* quantity is decoded. Returns that vlq.
*/
VLQ VlqFromFd(int fd)
{
VLQ vlqRead = 0;
unsigned char b = 0;
while (read(fd, &b, 1) == 1 && (b & 0x80))
vlqRead = (vlqRead << 7) | (b & 0x7F);
return (vlqRead << 7) | b;
}
/*
* VlqFromIrf: Reads bytes from file corresponding to given index until
* a variable length quantity is decoded. Returns that vlq.
*/
VLQ VlqFromIrf(unsigned irf)
{
VLQ vlqRead = 0;
unsigned char b = 0;
while ((b = ChGetIrf(irf)) & 0x80)
vlqRead = (vlqRead << 7) | (b & 0x7F);
return (vlqRead << 7) | b;
}
/*
* LongFromFd: Reads number of bytes from Fd until number is in.
*/
unsigned long LongFromFd(int fd, unsigned cb)
{
unsigned char rgb[4];
unsigned long longT = 0;
unsigned ib = 0;
read(fd, rgb, cb);
for (; ib < cb; ib++)
longT = (longT << 8) + rgb[ib];
return longT;
}
/*
* Addnote: Given channel, pitch, instrument, and volume will add that
* note to the array of playing notes.
*
* date: 30/6/1994 - added chan as well as pfx init
*/
void Addnote(int chan, int pitch, int inst, int vol)
{
NRL *pnrlT;
if (0 > pitch || 127 < pitch || 0 > chan || 15 < chan)
return;
pnrlT = (NRL *) malloc(sizeof(NRL)); /** Allocate space **/
pnrlT->pnrl = rgpnrl[chan][pitch];
rgpnrl[chan][pitch] = pnrlT; /** Attach to front of list in array **/
pnrlT->inst = inst;
pnrlT->vol = vol;
pnrlT->pfxTail = NULL;
pnrlT->ptuneNow = ptuneCurr;
}
/*
* PeiRequestPtune: Returns a pointer to a new event structure at the
* position in the tune specified.
*/
EI *PeiRequestPtune(Tune *ptune)
{
EI *pei;
pei = (EI *) malloc(sizeof(EI)); /** Allocate space for event **/
pei->pei = ptune->pei;
ptune->pei = pei; /** Attach to front of event list at tune position **/
return pei;
}
/*
* Endnote: Given a pitch and instrument, will remove a note from array
* of playing notes and store it as an event in the tune.
*
* date: 30/6/1994 - added support for effects, 16 chans, min. perc. durat.
*/
void Endnote(int chan, int pitch, int inst)
{
NRL *pnrlT, *pnrlOld = NULL;
unsigned long durat;
EI *peiT;
if (0 > pitch || 127 < pitch || 0 > chan || 15 < chan)
return;
for (pnrlT = rgpnrl[chan][pitch]; NULL != pnrlT && pnrlT->inst != inst; ) {
pnrlOld = pnrlT;
pnrlT = pnrlT->pnrl;
} /** Find instrument in hanging-note array **/
if (NULL == pnrlT)
return;
durat = ptuneCurr->count - pnrlT->ptuneNow->count; /** Calc. duration **/
if (0 > inst && wDivision / 2 > durat)
durat = wDivision / 2; /** Percussion sounds have a min. duration **/
if (durat < wQuant)
durat = wQuant; /** All sounds have a min. duration **/
peiT = PeiRequestPtune(pnrlT->ptuneNow); /** Get an event **/
peiT->effect = durat;
peiT->inst = inst; /** Store the note in it **/
peiT->pitch = pitch;
peiT->vol = pnrlT->vol;
peiT->pfxTail = pnrlT->pfxTail;
if (NULL == pnrlOld) /** Remove note from hanging-note array **/
rgpnrl[chan][pitch] = pnrlT->pnrl;
else
pnrlOld->pnrl = pnrlT->pnrl;
free(pnrlT);
}
/*
* VlqInterpIrf: Reads a file pointer and gathers all notes at this
* instant, storing them on the note stack. Returns ticks until next
* collection of notes. A running status of current channel is maintained.
*
* date: 30/6/1994 - added effect support
*/
VLQ VlqInterpIrf(unsigned irf, unsigned *pbStat)
{
unsigned bEvent;
VLQ vlqT;
FX *pfx;
do { /** Loop.. **/
bEvent = ChGetIrf(irf); /** Get first data byte **/
if (0x80 <= bEvent && 0xEF >= bEvent) { /** If a command **/
*pbStat = bEvent; /** update running-status byte **/
bEvent = ChGetIrf(irf); /** and get next data byte **/
}
if (0xF0 == bEvent || 0xF7 == bEvent) /** If a sys-exclusive message **/
SkipIrf(irf, VlqFromIrf(irf)); /** skip it **/
else if (0xFF == bEvent) { /** Else if a meta event **/
bEvent = ChGetIrf(irf); /** get type of event **/
vlqT = VlqFromIrf(irf); /** and length **/
if (0x2F == bEvent) { /*** If termination event ***/
close(prf[irf].fd); /*** close handle ***/
prf[irf].fd = -1;
vlqT = 0;
break; /*** and terminate ***/
}
if (0x51 == bEvent) { /*** Else if tempo event ***/
unsigned long t;
EI *pei;
t = (unsigned long) ChGetIrf(irf) << 16; /*** get value ***/
t += (unsigned long) ChGetIrf(irf) << 8;
t += ChGetIrf(irf);
pei = PeiRequestPtune(ptuneCurr);
pei->effect = 60000000L / wQuant * wDivision / t; /*** and convert ***/
pei->pitch = -1;
} else
SkipIrf(irf, vlqT); /*** Else skip event ***/
} else
switch (*pbStat & 0xF0) { /** Else must be a midi event.. **/
case 0x80:
case 0x90: { /** Note on/off **/
unsigned bVol, bChan;
bVol = ChGetIrf(irf);
bChan = *pbStat & 0x0F;
if (0 < bVol && 0x90 <= *pbStat)
if (bChan != bDrumch)
Addnote(bChan, bEvent, rgbPatch[bChan], bVol);
else
Addnote(bChan, 0, -1 - bEvent, bVol);
else
if (bChan != bDrumch)
Endnote(bChan, bEvent, rgbPatch[bChan]);
else
Endnote(bChan, 0, -1 - bEvent);
break;
}
case 0xA0: { /** Polyphonic Key Pressure **/
NRL *pnrlT;
unsigned bChan;
bChan = *pbStat & 0x0F;
pnrlT = rgpnrl[bChan][bEvent];
while (NULL != pnrlT && pnrlT->inst != rgbPatch[bChan])
pnrlT = pnrlT->pnrl;
if (NULL != pnrlT) {
pfx = (FX *) malloc(sizeof(FX));